package com.ericsson.middleware;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.*;
import javax.servlet.http.HttpServlet;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.ericsson.middleware.ContextBroker.ContextBrokerClient;
import com.ericsson.middleware.ContextBroker.RootSubscribeResponse;
import com.ericsson.middleware.ContextBroker.SubscribeContext;
import com.ericsson.middleware.ContextBroker.UnsubscribeContext;
import com.ericsson.middleware.ContextBroker.UpdateContext;
import com.ericsson.middleware.ContextBroker.UpdateContextResponse;
import com.ericsson.middleware.dao.MySQLDBCreator;
import com.ericsson.middleware.entities.LampState;
import com.ericsson.middleware.entities.ParkingSpotState;
import com.ericsson.middleware.service.LampService;
import com.ericsson.middleware.service.ParkingSpotService;
import com.ericsson.middleware.slsp.ParkingSpot;
import com.ericsson.middleware.slsp.Record;
import com.ericsson.middleware.slsp.RecordList;
import com.ericsson.middleware.slsp.SmartLightningClient;
import com.ericsson.middleware.slsp.SmartParkingClient;
import com.ericsson.middleware.utils.JsonUtil;
import com.ericsson.middleware.utils.StringNormalizer;

/**
 * @author xgedsan
 */

@SuppressWarnings("serial")
public class Startup extends HttpServlet {
	private final static Logger LOGGER = Logger.getLogger(Startup.class
			.getName());

	public void init() throws ServletException {
		LOGGER.log(Level.INFO, "Starting App: ");

		LOGGER.log(Level.INFO, "*****AQUI 0");
		// load context
////		@SuppressWarnings("resource")
//		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(
//				"config.xml");

		LOGGER.log(Level.INFO, "*****AQUI -1");
		// load properties
		PropertiesProvider.loadProperties();

		LOGGER.log(Level.INFO, "*****AQUI 1");
		// initialize database
//		MySQLDBCreator dbCreator = (MySQLDBCreator) applicationContext.getBean("mySQLDBCreator");
		MySQLDBCreator dbCreator = new  MySQLDBCreator();
		try {
			LOGGER.log(Level.INFO, "*****AQUI 3");
			dbCreator.checkAndCreate();
			LOGGER.log(Level.INFO, "*****AQUI 4");
		} catch (Exception e) {
			LOGGER.log(Level.SEVERE, "Failed to initialize database: " + e.getMessage());
		}
		LOGGER.log(Level.INFO, "*****AQUI 2");
//
//		LampService lampService = (LampService) applicationContext.getBean("lampService");		
//		ParkingSpotService parkingSpotService = (ParkingSpotService) applicationContext.getBean("parkingSpotService");	
////		LampService lampService =  new LampService();	
////		ParkingSpotService parkingSpotService = new ParkingSpotService();
//
//		// get all lamps, update database and Context Broker. Subscriber for context changes
//		initializeLamps(lampService);
//		// get all parking spots, update database and Context Broker
//		initializeParkingSpots(parkingSpotService);

	}

	void initializeLamps(LampService lampService) {
		// initialize Session ID
		SmartLightningClient client = new SmartLightningClient();
		client.refreshLampSessionID();

		// will be used on subscribe context
		List<String> branchPatterns = new ArrayList<String>();

		// get all lamps and send to database
		RecordList lamps = client.getLamps();
		ContextBrokerClient cbClient = new ContextBrokerClient();

		for (Record temp : lamps.getRecord()) {
			LampState newLamp = new LampState(temp.getBranchName() + "_" + temp.getLuminaireName(), temp.getSerialID(), temp.getCurrentIntensity(), temp.getPWM(), temp.getTimestamp(), temp.getLat(), temp.getLong());

			//fill this list with different streets 
			if (!branchPatterns.contains(temp.getBranchName())){
				branchPatterns.add(temp.getBranchName());
			}

			try {
				LampState fromDB = null;
				fromDB = lampService.searchById(newLamp.getId());
				if (fromDB != null) {
					LOGGER.log(Level.INFO, "Retrieved Lamp " + fromDB.getId() + " is already on database");
					//TODO verify conditions
					if (!fromDB.getPWM().equals(newLamp.getPWM()) || !fromDB.getSerialID().equals(newLamp.getSerialID())) {
						lampService.update(newLamp);

						// build updateContext and send to Context Broker						
						UpdateContext updateContext = cbClient.buildUpdateContext(PropertiesProvider.getLAMPS_TYPE(), PropertiesProvider.getUPDATE_ACTION_UPDATE(), temp);
						LOGGER.log(Level.INFO, "UPDATE request: " + JsonUtil.toJson(updateContext));
						UpdateContextResponse response = cbClient.sendUpdateContextWithReAttempts(JsonUtil.toJson(updateContext), Integer.parseInt(PropertiesProvider.getUPDATE_REATTEMPTS()));
						LOGGER.log(Level.INFO, "UPDATE response: " + JsonUtil.toJson(response));
					}
					else {
						LOGGER.log(Level.INFO, "Lamp " + newLamp.getId() + " is up to date on database");		
					}
				}
				else {
					lampService.save(newLamp);
					// build updateContext and send to Context Broker
					UpdateContext updateContext = cbClient.buildUpdateContext(PropertiesProvider.getLAMPS_TYPE(), PropertiesProvider.getUPDATE_ACTION_APPEND(), temp);					
					LOGGER.log(Level.INFO, "APPEND request: " + JsonUtil.toJson(updateContext));					
					UpdateContextResponse response = cbClient.sendUpdateContextWithReAttempts(JsonUtil.toJson(updateContext), Integer.parseInt(PropertiesProvider.getUPDATE_REATTEMPTS()));
					LOGGER.log(Level.INFO, "APPEND response: " + JsonUtil.toJson(response));
				}
			} catch (Exception e) {
				LOGGER.log(Level.SEVERE, "Failed to save Lamp on database: " + e.getMessage());
			}									
		}

		// remove last subscriptions
		for (String subscribid : PropertiesProvider.getSubscriptionIdProperty()) {
			cbClient.sendUnSubscribeContext(JsonUtil.toJson(new UnsubscribeContext(subscribid)));
		}
		// subscribe for context update
		List<String> subscriptionids = new ArrayList<String>();
		for (String branch : branchPatterns) {
			SubscribeContext subscribeContext = cbClient.buildSubscribeContext(branch, PropertiesProvider.getLAMPS_TYPE());

			LOGGER.log(Level.INFO, "SUBSCRIBE request: " + JsonUtil.toJson(subscribeContext));
			RootSubscribeResponse subscribeContextResponse = cbClient.sendSubscribeContext(JsonUtil.toJson(subscribeContext));
			subscriptionids.add(subscribeContextResponse.getSubscribeResponse().getSubscriptionId());

			LOGGER.log(Level.INFO, "Subscribe response: " + JsonUtil.toJson(subscribeContextResponse));
		}
		PropertiesProvider.setSubscriptionIdProperty(subscriptionids);
	}


	void initializeParkingSpots(ParkingSpotService parkingSpotService) {

		SmartParkingClient client = new SmartParkingClient();

		// get all parking spots and send to database
		ParkingSpot[] parkingSpots = client.getParkingSpots();
		ContextBrokerClient cbClient = new ContextBrokerClient();

		for (ParkingSpot temp : parkingSpots) {
			ParkingSpotState newParkingSpot = new ParkingSpotState(StringNormalizer.normalize(temp.getStreetAddress() + "_" + temp.getAddress()), temp.getStatus(), temp.getLat(), temp.getLng());

			try {
				ParkingSpotState fromDB = null;
				fromDB = parkingSpotService.searchById(newParkingSpot.getId());
				if (fromDB != null) {
					LOGGER.log(Level.INFO, "Retrieved Parking Spot " + fromDB.getId() + " is already on database");

					if (!fromDB.getStatus().equals(newParkingSpot.getStatus())) {
						parkingSpotService.update(newParkingSpot);

						// build updateContext and send to Context Broker						
						UpdateContext updateContext = cbClient.buildUpdateContext(PropertiesProvider.getPARKING_SPOTS_TYPE(), PropertiesProvider.getUPDATE_ACTION_UPDATE(), temp);
						LOGGER.log(Level.INFO, "UPDATE request: " + JsonUtil.toJson(updateContext));
						UpdateContextResponse response = cbClient.sendUpdateContextWithReAttempts(JsonUtil.toJson(updateContext), Integer.parseInt(PropertiesProvider.getUPDATE_REATTEMPTS()));
						LOGGER.log(Level.INFO, "UPDATE response: " + JsonUtil.toJson(response));
					}
					else {
						LOGGER.log(Level.INFO, "Parking Spot " + newParkingSpot.getId() + " is up to date on database");		
					}
				}
				else {
					parkingSpotService.save(newParkingSpot);
					// build updateContext and send to Context Broker
					UpdateContext updateContext = cbClient.buildUpdateContext(PropertiesProvider.getPARKING_SPOTS_TYPE(), PropertiesProvider.getUPDATE_ACTION_APPEND(), temp);
					LOGGER.log(Level.INFO, "APPEND request: " + JsonUtil.toJson(updateContext));				
					UpdateContextResponse response = cbClient.sendUpdateContextWithReAttempts(JsonUtil.toJson(updateContext), Integer.parseInt(PropertiesProvider.getUPDATE_REATTEMPTS()));
					LOGGER.log(Level.INFO, "APPEND response: " + JsonUtil.toJson(response));
				}
			} catch (Exception e) {
				LOGGER.log(Level.SEVERE, "Failed to save Parking Spot on database: " + e.getMessage());
			}									
		}

	}

	@Override	
	public void destroy() {		
		super.destroy();
		LOGGER.log(Level.SEVERE, "Application finalized");

		ContextBrokerClient cbClient = new ContextBrokerClient();
		// remove last subscriptions
		for (String subscribid : PropertiesProvider.getSubscriptionIdProperty()) {
			cbClient.sendUnSubscribeContext(JsonUtil.toJson(new UnsubscribeContext(subscribid)));
		}
				
		PropertiesProvider.setSubscriptionIdProperty(new ArrayList<String>());
	}
}